package com.hmjk.health.util;

import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.Window;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.widget.ImageButton;

import com.hmjk.health.R;
import com.hmjk.health.zxing.camera.CameraManager;
import com.hmjk.health.zxing.decoding.QRScanDecoder;
import com.hmjk.health.zxing.view.ViewfinderView;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;

public class QRScanerActivity extends Activity implements Callback, ResultPointCallback{
	private final String TAG = QRScanerActivity.class.getSimpleName();
	private CameraManager mCameraManager = null;
	private ViewfinderView viewfinderView;
	private SurfaceView surfaceView;
	private SurfaceHolder surfaceHolder;
	private boolean surfaceCreated;
	private MediaPlayer mediaPlayer;
	private boolean playBeep;
	private static final float BEEP_VOLUME = 0.10f;
	private boolean vibrate;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.qrcode_scan_activity);
		ImageButton back = (ImageButton) findViewById(R.id.back);
		back.setOnClickListener(new View.OnClickListener(){

			@Override
			public void onClick(View arg0) {
				finish();
			}
		});
		
		surfaceView = (SurfaceView) findViewById(R.id.preview_view);
		surfaceHolder = surfaceView.getHolder();
		surfaceHolder.addCallback(this);
		
		viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view);
		
		surfaceCreated = false;
		
	}

	@Override
	protected void onResume()
	{
		super.onResume();
		
		if(surfaceCreated){
			startCamera();
		}

		playBeep = true;
		AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
		if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL)
		{
			playBeep = false;
		}
		initBeepSound();
		vibrate = true;
	}

	@Override
	protected void onPause()
	{
		super.onPause();
		stopCamera();
		clearMsg();
	}

	@Override
	protected void onDestroy()
	{
		stopCamera();
		super.onDestroy();
	}

	private void checkIdle(){
		mHandler.removeMessages(QRScanDecoder.MSG_DECODE_IDLE_LONGTIME);
		Message m = mHandler.obtainMessage(QRScanDecoder.MSG_DECODE_IDLE_LONGTIME);
		mHandler.sendMessageDelayed(m, 1000 * 60 * 5);
	}
	
	private void startCamera(){
		if(mCameraManager == null){
			mCameraManager = new CameraManager(this, mHandler);
			int w = surfaceView.getWidth();
			int h = surfaceView.getHeight();
			try {
				mCameraManager.open(surfaceHolder, w, h);
				viewfinderView.setFrameRect(mCameraManager.getFramingRect());
				mCameraManager.startPreview();
				mCameraManager.startScan();
				viewfinderView.drawViewfinder();
				checkIdle();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				stopCamera();
			}
			
		}
	}

	private void stopCamera(){
		if(mCameraManager != null){
			mCameraManager.stopPreview();
			mCameraManager.close();
		}
		mCameraManager = null;
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){}

	@Override
	public void surfaceCreated(SurfaceHolder holder){
		if(!surfaceCreated){
			surfaceCreated = true;
			startCamera();
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder){
		surfaceCreated = false;
		stopCamera();
	}
	
	private void clearMsg(){
		mHandler.removeMessages(QRScanDecoder.MSG_DECODE_IDLE_LONGTIME);
		mHandler.removeMessages(QRScanDecoder.MSG_AUTO_FOCUS);
		mHandler.removeMessages(QRScanDecoder.MSG_DECODE_OK);
		mHandler.removeMessages(QRScanDecoder.MSG_DECODE_FAIL);
	}
	
	private Handler mHandler = new Handler(){
		@Override
		public void handleMessage(Message msg){
			switch(msg.what){
			case QRScanDecoder.MSG_DECODE_IDLE_LONGTIME:{
				finish();
			}break;
			case QRScanDecoder.MSG_AUTO_FOCUS:{
				mCameraManager.autoFocus();
			}break;
			case QRScanDecoder.MSG_DECODE_OK:{
				Result r = (Result) msg.obj;
				
				playBeepSoundAndVibrate();
				
				String text = r.getText();
				Log.d(TAG, "MSG_DECODE_OK:"+text);
				Intent i = new Intent(text);
				setResult(RESULT_OK,i);
				finish();
			}break;
			case QRScanDecoder.MSG_DECODE_FAIL:{
				mCameraManager.resetDecoder();
			}break;
			}
		}
	};

	private void initBeepSound(){
		if (playBeep && mediaPlayer == null){
			// The volume on STREAM_SYSTEM is not adjustable, and users found it
			// too loud,
			// so we now play on the music stream.
			setVolumeControlStream(AudioManager.STREAM_MUSIC);
			mediaPlayer = new MediaPlayer();
			mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mediaPlayer.setOnCompletionListener(beepListener);

			AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
			try{
				mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
				file.close();
				mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
				mediaPlayer.prepare();
			}
			catch (IOException e){
				mediaPlayer = null;
			}
		}
	}

	private static final long VIBRATE_DURATION = 200L;

	private void playBeepSoundAndVibrate(){
		if (playBeep && mediaPlayer != null){
			mediaPlayer.start();
		}
		if (vibrate){
			Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
			vibrator.vibrate(VIBRATE_DURATION);
		}
	}

	/**
	 * When the beep has finished playing, rewind to queue up another one.
	 */
	private final OnCompletionListener beepListener = new OnCompletionListener(){
		public void onCompletion(MediaPlayer mediaPlayer){
			mediaPlayer.seekTo(0);
		}
	};

	
	@Override
	public void foundPossibleResultPoint(ResultPoint point) {
		viewfinderView.addPossibleResultPoint(point);
	}
}